using System;

namespace Tycho.Parser.Peg {
    public class EndBlockProduction : Production {
        private readonly IMemoClearer MemoClearer;
        public readonly IProduction IndentationTerminal;

        public EndBlockProduction (IMemoClearer memoClearer) {
            MemoClearer = memoClearer;
            IndentationTerminal = IndentationProduction.CreateTerminal ();
            ErrorInformation = new KeywordErrorInformation ("}");
        }

        protected override ParseResult ReallyParse (char[] source, int index, ParseContext context, string sourceString, ParseEnvironment parseEnvironment) {
            index = Whitespace.SkipWhitespace (source, index);

            if (context.BracketDepth > 0) {
                if (index < source.Length && source[index] == '}') {
                    ParseContext newContext = context.Clone ();
                    newContext.BracketDepth--;
                    return new ParseResult (index + 1, CreateTerm (index, 1, parseEnvironment), newContext);
                }
            } else if (index >= source.Length && !String.IsNullOrEmpty (context.LastIndent)) {
                ParseContext newContext = context.Clone ();
                newContext.LastIndent = null;
                return new ParseResult (source.Length, CreateTerm (source.Length, 0, parseEnvironment), newContext);
            }

            var indentResult = IndentationTerminal.Parse (source, index, context, sourceString, parseEnvironment);

            if (indentResult != null && context.BracketDepth == 0) {
                if (((IndentationTerm) indentResult.Term).GetIndentation (context.LastIndent)
                    == Indentation.EndBlock) {
                    int endOfWhitespaceIndex = Whitespace.SkipWhitespace (source, index);

                    if (endOfWhitespaceIndex == index) {
                        MemoClearer.ClearMemoFor (index, source);
                    }

                    ParseContext newContext = indentResult.Context.Clone ();
                    return new ParseResult (endOfWhitespaceIndex, CreateTerm (index, indentResult.Index - index, parseEnvironment), newContext);
                }
            }

            return null;
        }

        private static KeywordTerm CreateTerm (int index, int length, ParseEnvironment parseEnvironment) {
            return new KeywordTerm ("}",
                                    parseEnvironment.SourceFileInformation.CreateSourceInformation
                                        (index, length));
        }
    }
}